package top.yehonghan.handler;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
import top.yehonghan.dto.ResourceRoleDTO;
import top.yehonghan.entity.UserDetailsImpl;
import top.yehonghan.service.RedisService;
import top.yehonghan.util.JwtUtils;
import top.yehonghan.util.Result;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Objects;

import static top.yehonghan.constant.CommonConst.APPLICATION_JSON;
import static top.yehonghan.constant.JwtConstant.*;
import static top.yehonghan.constant.RedisPrefixConst.USER_TOKEN;

/**
 * ClassName: JwtAuthenticationTokenFilter
 * Description: jwt校验拦截器
 *
 * @Author: yehonghan
 * @Create: 2023/1/10 10:13
 * @Version: V1.0
 */
@Configuration
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private RedisService redisService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 获取用户请求方式
        String method = request.getMethod();
        // 获取用户请求Url
        String url = request.getRequestURI();
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        List<ResourceRoleDTO> resourceRoleList = FilterInvocationSecurityMetadataSourceImpl.getResourceRoleList();
        boolean isCheckToken = false;
        //拦截需要权限访问的接口，并校验token，不需要权限访问的接口不用校验token
        for (ResourceRoleDTO resourceRoleDTO : resourceRoleList) {
            if (antPathMatcher.match(resourceRoleDTO.getUrl(), url) && resourceRoleDTO.getRequestMethod().equals(method)) {
                isCheckToken = true;
                break;
            }
        }
        if (!isCheckToken) {
            //不需要校验token的放行
            filterChain.doFilter(request, response);
            return;
        }
        //获取token
        String token = request.getHeader("authorization");
        if (StringUtils.isEmpty(token)) {
            response.setContentType(APPLICATION_JSON);
            response.getWriter().write(JSON.toJSONString(Result.fail(JWT_ERRCODE_NULL,"token为空")));
            return;
        }
        //解析token
        String userName;
        try {
            Claims claims = JwtUtils.parseJWT(token);
            userName = claims.getSubject();
        } catch (Exception e) {
            e.printStackTrace();
            response.setContentType(APPLICATION_JSON);
            response.getWriter().write(JSON.toJSONString(Result.fail(JWT_ERRCODE_EXPIRE,"token已过期")));
            return;
        }
        //从redis中获取用户信息
        String userJSON = JSON.toJSONString(redisService.get(USER_TOKEN + ":" + userName));
        UserDetailsImpl loginUser = JSON.parseObject(userJSON, UserDetailsImpl.class);
        if (Objects.isNull(loginUser)) {
            response.setContentType(APPLICATION_JSON);
            response.getWriter().write(JSON.toJSONString(Result.fail(JWT_ERRCODE_FAIL,"token校验失败")));
            return;
        }
        //获取权限信息存入SecurityContextHolder
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //放行
        filterChain.doFilter(request, response);
    }
}
